﻿using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using DeepEarth.Core.Utilities;
using DeepEarth.Map.Core;
using DeepEarth.Toolkit.Common;

namespace DeepEarth.Toolkit.Controls
{
    [TemplatePart(Name = PART_ToggleButton, Type = typeof(ToggleButton))]
    [TemplateVisualState(Name = VSM_Normal, GroupName = VSM_CommonStates)]
    [TemplateVisualState(Name = VSM_MouseOver, GroupName = VSM_CommonStates)]
    [TemplateVisualState(Name = VSM_Open, GroupName = VSM_OperationStates)]
    [TemplateVisualState(Name = VSM_Closed, GroupName = VSM_OperationStates)]
    [TemplateVisualState(Name = VSM_Visible, GroupName = VSM_ToggleButtonStates)]
    [TemplateVisualState(Name = VSM_Hidden, GroupName = VSM_ToggleButtonStates)]
    public class MeasureTool : MapInteractionControl
    {
        const string PART_ToggleButton = "PART_ToggleButton";

        #region Visual States
        const string VSM_CommonStates = "CommonStates";
        const string VSM_MouseOver = "MouseOver";
        const string VSM_Normal = "Normal";

        const string VSM_OperationStates = "OperationStates";
        const string VSM_Open = "Open";
        const string VSM_Closed = "Closed";

        const string VSM_ToggleButtonStates = "ToggleButtonStates";
        const string VSM_Visible = "Visible";
        const string VSM_Hidden = "Hidden";
        #endregion

        DynamicLayer drawLayer = new DynamicLayer();
        ToggleButton toggleButton;
        bool isMouseOver;
        KeyEventHandler keyHandler;

        public MeasureTool()
        {
            DefaultStyleKey = typeof(MeasureTool);

            RulerToggleCommand = new LambdaCommand(OnRulerToggle);
            clearCommand = new LambdaCommand(OnClear);
            resumeCommand = new LambdaCommand(Resume);

            this.resumeCommand.IsEnabled = false;
            this.clearCommand.IsEnabled = false;

            keyHandler = new KeyEventHandler(Digitizer_KeyDown);

            Model = new MeasureToolModel(this.Map, this.drawLayer);
            Model.DrawComplete += (o, e) => EndMeasure();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            toggleButton = (ToggleButton)GetTemplateChild(PART_ToggleButton);

            GoToState(true);
        }

        #region Properties
        public static readonly DependencyProperty ModelProperty = DependencyProperty.Register("Model", typeof(MeasureToolModel), typeof(MeasureTool), null);
        public MeasureToolModel Model
        {
            get { return (MeasureToolModel)GetValue(ModelProperty); }
            set { SetValue(ModelProperty, value); }
        }

        public static readonly DependencyProperty IsMeasuringProperty = DependencyProperty.Register("IsMeasuring", typeof(bool), typeof(MeasureTool), new PropertyMetadata(IsMeasuringChanged));
        public bool IsMeasuring
        {
            get { return (bool)GetValue(IsMeasuringProperty); }
            set { SetValue(IsMeasuringProperty, value); }
        }

        static void IsMeasuringChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            MeasureTool self = sender as MeasureTool;

            if (args.NewValue != null)
            {
                bool isMeasuring = (bool)args.NewValue;

                if (isMeasuring)
                    self.BeginMeasure();
                else
                    self.Clear();

                self.GoToState(true);
            }
        }

        bool showToggleButton = true;
        public bool ShowToggleButton
        {
            get { return showToggleButton; }
            set
            {
                if (value != showToggleButton)
                {
                    showToggleButton = value;
                    GoToState(true);
                }
            }
        }
        #endregion

        #region Commands
        public static readonly DependencyProperty RulerToggleCommandProperty = DependencyProperty.Register("RulerToggleCommand", typeof(ICommand), typeof(MeasureTool), null);
        public ICommand RulerToggleCommand
        {
            get { return (ICommand)GetValue(RulerToggleCommandProperty); }
            set { SetValue(RulerToggleCommandProperty, value); }
        }

        void OnRulerToggle()
        {
            if (toggleButton != null)
            {
                IsMeasuring = toggleButton.IsChecked.GetValueOrDefault(false);
                GoToState(true);
            }
        }

        LambdaCommand clearCommand;
        public LambdaCommand ClearCommand
        {
            get { return clearCommand; }
        }

        void OnClear()
        {
            Clear();
            BeginMeasure();
        }

        LambdaCommand resumeCommand;
        public LambdaCommand ResumeCommand
        {
            get { return resumeCommand; }
        }
        #endregion
       
        void BeginMeasure()
        {
            this.Map.InteractionSurface.IsHitTestVisible = true;
            Application.Current.RootVisual.AddHandler(FrameworkElement.KeyDownEvent, keyHandler, true);
            this.Map.OverlayPanel.Children.Add(drawLayer);

            Model.BeginMeasure();
            this.resumeCommand.IsEnabled = Model.CanResume;
            this.clearCommand.IsEnabled = Model.CanClear;
        }

        void EndMeasure()
        {
            Model.EndMeasure();

            Application.Current.RootVisual.RemoveHandler(FrameworkElement.KeyDownEvent, keyHandler);
            this.Map.InteractionSurface.IsHitTestVisible = false;
            this.resumeCommand.IsEnabled = Model.CanResume;
            this.clearCommand.IsEnabled = Model.CanClear;
        }

        void Clear()
        {
            drawLayer.Children.Clear();
            this.Map.OverlayPanel.Children.Remove(drawLayer);

            Model.Clear();

            EndMeasure();
        }

        void Resume()
        {
            Application.Current.RootVisual.AddHandler(FrameworkElement.KeyDownEvent, keyHandler, true);
            this.resumeCommand.IsEnabled = false;
            this.Map.InteractionSurface.IsHitTestVisible = true;

            Model.Resume();
        }

        #region Event Handlers
        protected override void MapChanged(IMap newMap, IMap oldMap)
        {
            if (Model != null)
            {
                Model.Map = newMap;
            }
        }

        void mouseLeave(object sender, MouseEventArgs e)
        {
            isMouseOver = false;
            GoToState(true);
        }

        void mouseEnter(object sender, MouseEventArgs e)
        {
            isMouseOver = true;
            GoToState(true);
        }

        // Keyboard
        void Digitizer_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Left:
                    this.Map.Pan(-200, 0);
                    break;

                case Key.Right:
                    this.Map.Pan(200, 0);
                    break;

                case Key.Up:
                    this.Map.Pan(0, -150);
                    break;

                case Key.Down:
                    this.Map.Pan(0, 150);
                    break;

                case Key.Escape:
                    if (Model.IsValidShape())
                    {
                        EndMeasure();
                    }
                    else
                    {
                        Clear();
                        BeginMeasure();
                    }
                    break;

                default:
                    break;
            }
        }
        #endregion

        void GoToState(bool useTransitions)
        {
            VisualStateManager.GoToState(this, isMouseOver ? VSM_MouseOver : VSM_Normal, useTransitions);
            VisualStateManager.GoToState(this, IsMeasuring ? VSM_Open : VSM_Closed, useTransitions);
            VisualStateManager.GoToState(this, ShowToggleButton ? VSM_Visible : VSM_Hidden, useTransitions);
        }
    }
}